<?php

namespace App\Trip\Train\Order\Impl;

use App\Models\Setting\Setting;
use App\Models\Train\TrainOrderPassengers\TrainOrderPassenger;
use App\Models\Train\TrainOrders\TrainOrder;
use App\Models\Trip\TripOrderRefund\TripOrderPassengerRefundDetail;
use App\Trip\Train\Order\Interfaces\OrderPassengerRefundInterface;
use App\Trip\Train\Providers\PiaoChi\TrainOrderService;
use Exception;

class PiaoChiOrderPassengerRefundImpl implements OrderPassengerRefundInterface
{

    private TrainOrder          $order_info;
    private TrainOrderPassenger $passenger;
    private float               $should_refund_amount   = 0;
    private float               $should_pay_amount      = 0;
    private float               $ticket_refund_amount   = 0;
    private float               $refund_service_amount  = 0;
    private float               $selected_seat_amount   = 0;
    private float               $ticket_loss_amount     = 0;
    private bool                $ignore_work_time_error = false;

    /**
     * @throws Exception
     */
    public function __construct(TrainOrder $order_info, TrainOrderPassenger $passenger)
    {
        $this->order_info = $order_info;
        $this->passenger  = $passenger;
        $this->calcAmount();
    }

    /**
     * @throws Exception
     */
    private function calcAmount()
    {
        $order_info  = $this->getOrderInfo();
        $asset_price = $this->passenger->getTicketPrice();
        $pc          = new TrainOrderService();
        $diff        = $pc->calcPriceDiff($order_info->getTrainDate(), $pc::PRICE_DIFF_TYPE_REFUND, $asset_price);
        if ($diff > 0) {
            $this->ticket_refund_amount = $diff;
            $this->ticket_loss_amount   = $asset_price - $diff;
        }
        /**
         * 退票手续费
         */
        $setting                     = new Setting();
        $refund_service_fee          = $setting->TrainOfflineRefundServiceFee();
        $this->refund_service_amount = $refund_service_fee;
        /**
         * @var float $select_seat_fee 选座费
         */
        $select_seat_fee = 0;
        if ($this->passenger->isMatchedSeat()) {
            $refundDetailModel = new TripOrderPassengerRefundDetail();
            if (!$refundDetailModel->getPassengerSelectSeatRefund($this->passenger, $order_info->getPaySn())) {
                $select_seat_fee = $this->passenger->getSelectedSeatPrice();
            }
        }
        $this->selected_seat_amount = $select_seat_fee;

        /**
         * 退款金额  =扣除票损的票价 - 购票服务费 + 选座服务费
         */
        $calc_amount = $diff - $refund_service_fee + $select_seat_fee;
        if ($calc_amount > 0) {
            $this->should_refund_amount = $calc_amount;
            $this->should_pay_amount    = 0;
        } else if ($calc_amount < 0) {
            $this->should_refund_amount = 0;
            $this->should_pay_amount    = $calc_amount;
        } else {
            $this->should_refund_amount = 0;
            $this->should_pay_amount    = 0;
        }

    }

    public function getOrderInfo(): TrainOrder
    {
        return $this->order_info;
    }

    public function getPassenger(): TrainOrderPassenger
    {
        return $this->passenger;
    }

    /**
     * 当前应退金额
     *
     * @throws Exception
     */
    public function getShouldRefundAmount(): float
    {
        return $this->should_refund_amount;
    }

    /**
     * 返回正数
     *
     * @throws Exception
     */
    public function getShouldPayAmount(): float
    {
        return abs($this->should_pay_amount);
    }

    public function ticketRefundAmount(): float
    {
        return $this->ticket_refund_amount;
    }

    public function getRefundServiceAmount(): float
    {
        return $this->refund_service_amount;
    }

    public function getSelectedSeatAmount(): float
    {
        return $this->selected_seat_amount;
    }

    public function ticketLossAmount(): float
    {
        return $this->ticket_loss_amount;
    }

    public function isIgnoreWorkTimeError(): bool
    {
        return $this->ignore_work_time_error;
    }

    public function setIgnoreWorkTimeError(): static
    {
        $this->ignore_work_time_error = true;
        return $this;
    }
}